<chapter id="TextWidgetObjects">
<title>Multiline Text Editor</title>
- <xi:include href="xml/text_widget.xml" />
+ <xi:include href="section-text-widget.xml" />
<xi:include href="xml/gtktextiter.xml" />
<xi:include href="xml/gtktextmark.xml" />
<xi:include href="xml/gtktextbuffer.xml" />
<chapter id="TreeWidgetObjects">
<title>Tree, List and Icon Grid Widgets</title>
- <xi:include href="xml/tree_widget.xml" />
+ <xi:include href="section-tree-widget.xml" />
<xi:include href="xml/gtktreemodel.xml" />
<xi:include href="xml/gtktreeselection.xml" />
<xi:include href="xml/gtktreeviewcolumn.xml" />
'gtk4-widget-factory.xml',
'overview.xml',
'question_index.xml',
- 'text_widget.xml',
- 'tree_widget.xml',
'visual_index.xml',
]
expand_content_files = [
'question_index.xml',
- 'text_widget.xml',
- 'tree_widget.xml',
]
expand_content_md_files = [
'osx.md',
'wayland.md',
'windows.md',
-: 'x11.md',
+ 'x11.md',
'getting_started.md',
'resources.md',
'building.md',
'input-handling.md',
'drawing-model.md',
'css-overview.md',
- 'css-properties.md'
+ 'css-properties.md',
+ 'section-text-widget.md',
+ 'section-tree-widget.md',
]
types_conf = configuration_data()
--- /dev/null
+# Text Widget Overview {#TextWidget}
+
+GTK has an extremely powerful framework for multiline text editing. The
+primary objects involved in the process are #GtkTextBuffer, which represents the
+text being edited, and #GtkTextView, a widget which can display a #GtkTextBuffer.
+Each buffer can be displayed by any number of views.
+
+One of the important things to remember about text in GTK is that it's in
+the UTF-8 encoding. This means that one character can be encoded as multiple
+bytes. Character counts are usually referred to as _offsets_, while byte
+counts are called _indexes_. If you confuse these two, things will work fine
+with ASCII, but as soon as your buffer contains multibyte characters, bad
+things will happen.
+
+Text in a buffer can be marked with _tags_. A tag is an attribute that can
+be applied to some range of text. For example, a tag might be called "bold"
+and make the text inside the tag bold. However, the tag concept is more
+general than that; tags don't have to affect appearance. They can instead
+affect the behavior of mouse and key presses, "lock" a range of text so the
+user can't edit it, or countless other things. A tag is represented by a
+#GtkTextTag object. One #GtkTextTag can be applied to any number of text
+ranges in any number of buffers.
+
+Each tag is stored in a #GtkTextTagTable. A tag table defines a set of
+tags that can be used together. Each buffer has one tag table associated with
+it; only tags from that tag table can be used with the buffer. A single tag
+table can be shared between multiple buffers, however.
+
+Tags can have names, which is convenient sometimes (for example, you can name
+your tag that makes things bold "bold"), but they can also be anonymous (which
+is convenient if you're creating tags on-the-fly).
+
+Most text manipulation is accomplished with _iterators_, represented by a
+#GtkTextIter. An iterator represents a position between two characters in
+the text buffer. #GtkTextIter is a struct designed to be allocated on the
+stack; it's guaranteed to be copiable by value and never contain any
+heap-allocated data. Iterators are not valid indefinitely; whenever the
+buffer is modified in a way that affects the number of characters in the
+buffer, all outstanding iterators become invalid. (Note that deleting 5
+characters and then reinserting 5 still invalidates iterators, though you
+end up with the same number of characters you pass through a state with a
+different number).
+
+Because of this, iterators can't be used to preserve positions across buffer
+modifications. To preserve a position, the #GtkTextMark object is ideal. You
+can think of a mark as an invisible cursor or insertion point; it floats in
+the buffer, saving a position. If the text surrounding the mark is deleted,
+the mark remains in the position the text once occupied; if text is inserted
+at the mark, the mark ends up either to the left or to the right of the new
+text, depending on its _gravity_. The standard text cursor in left-to-right
+languages is a mark with right gravity, because it stays to the right of
+inserted text.
+
+Like tags, marks can be either named or anonymous. There are two marks
+built-in to #GtkTextBuffer; these are named "insert" and "selection_bound"
+and refer to the insertion point and the boundary of the selection which
+is not the insertion point, respectively. If no text is selected, these
+two marks will be in the same position. You can manipulate what is selected
+and where the cursor appears by moving these marks around.
+
+If you want to place the cursor in response to a user action, be sure to use
+gtk_text_buffer_place_cursor(), which moves both at once without causing a
+temporary selection (moving one then the other temporarily selects the range in
+between the old and new positions).
+
+Text buffers always contain at least one line, but may be empty (that
+is, buffers can contain zero characters). The last line in the text
+buffer never ends in a line separator (such as newline); the other
+lines in the buffer always end in a line separator. Line separators
+count as characters when computing character counts and character
+offsets. Note that some Unicode line separators are represented with
+multiple bytes in UTF-8, and the two-character sequence "\r\n" is also
+considered a line separator.
+
+Text buffers support undo and redo if gtk_text_buffer_set_enable_undo()
+has been set to %TRUE. Use gtk_text_buffer_undo() or gtk_text_buffer_redo()
+to perform the necessary action. Note that these operations are ignored if
+the buffer is not editable. Developers may want some operations to not be
+undoable. To do this, wrap your changes in
+gtk_text_buffer_begin_irreversible_action() and
+gtk_text_buffer_end_irreversible_action().
+
+## Simple Example
+
+The simplest usage of #GtkTextView might look like this:
+
+``` {.c}
+GtkWidget *view;
+GtkTextBuffer *buffer;
+
+view = gtk_text_view_new ();
+
+buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+gtk_text_buffer_set_text (buffer, "Hello, this is some text", -1);
+
+/* Now you might put the view in a container and display it on the
+ * screen; when the user edits the text, signals on the buffer
+ * will be emitted, such as "changed", "insert_text", and so on.
+ */
+```
+
+In many cases it's also convenient to first create the buffer with
+gtk_text_buffer_new(), then create a widget for that buffer with
+gtk_text_view_new_with_buffer(). Or you can change the buffer the widget
+displays after the widget is created with gtk_text_view_set_buffer().
+
+## Example of Changing Text Attributes
+
+The way to affect text attributes in #GtkTextView is to
+apply tags that change the attributes for a region of text.
+For text features that come from the theme — such as font and
+foreground color -- use CSS to override their default values.
+
+```
+GtkWidget *view;
+GtkTextBuffer *buffer;
+GtkTextIter start, end;
+PangoFontDescription *font_desc;
+GdkRGBA rgba;
+GtkTextTag *tag;
+GtkCssProvider *provider;
+GtkStyleContext *context;
+
+view = gtk_text_view_new ();
+
+buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+gtk_text_buffer_set_text (buffer, "Hello, this is some text", -1);
+
+/* Change default font and color throughout the widget */
+provider = gtk_css_provider_new ();
+gtk_css_provider_load_from_data (provider,
+ "textview {"
+ " font: 15 serif;"
+ " color: green;"
+ "}",
+ -1);
+context = gtk_widget_get_style_context (view);
+gtk_style_context_add_provider (context,
+ GTK_STYLE_PROVIDER (provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+/* Change left margin throughout the widget */
+gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 30);
+
+/* Use a tag to change the color for just one part of the widget */
+tag = gtk_text_buffer_create_tag (buffer, "blue_foreground",
+ "foreground", "blue",
+ NULL);
+gtk_text_buffer_get_iter_at_offset (buffer, &start, 7);
+gtk_text_buffer_get_iter_at_offset (buffer, &end, 12);
+gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
+```
+
+The `gtk4-demo` application that comes with
+GTK contains more example code for #GtkTextView.
--- /dev/null
+# Tree and List Widget Overview {#TreeWidget}
+
+To create a tree or list in GTK, use the #GtkTreeModel interface in
+conjunction with the #GtkTreeView widget. This widget is designed around
+a _Model/View/Controller_ design and consists of four major parts:
+
+- The tree view widget (GtkTreeView)
+- The view column (GtkTreeViewColumn)
+- The cell renderers (GtkCellRenderer etc.)
+- The model interface (GtkTreeModel)
+
+The _View_ is composed of the first three objects, while the last is the
+_Model_. One of the prime benefits of the MVC design is that multiple views
+can be created of a single model. For example, a model mapping the file
+system could be created for a file manager. Many views could be created
+to display various parts of the file system, but only one copy need be
+kept in memory.
+
+The purpose of the cell renderers is to provide extensibility to the
+widget and to allow multiple ways of rendering the same type of data.
+For example, consider how to render a boolean variable. Should it
+render it as a string of "True" or "False", "On" or "Off", or should
+it be rendered as a checkbox?
+
+## Creating a model
+
+GTK provides two simple models that can be used: the #GtkListStore
+and the #GtkTreeStore. GtkListStore is used to model list widgets,
+while the GtkTreeStore models trees. It is possible to develop a new
+type of model, but the existing models should be satisfactory for all
+but the most specialized of situations. Creating the model is quite
+
+``` {.c}
+GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+```
+
+This creates a list store with two columns: a string column and a boolean
+column. Typically the 2 is never passed directly like that; usually an
+enum is created wherein the different columns are enumerated, followed by
+a token that represents the total number of columns. The next example will
+illustrate this, only using a tree store instead of a list store. Creating
+a tree store operates almost exactly the same.
+
+``` {.c}
+enum
+{
+ TITLE_COLUMN,
+ AUTHOR_COLUMN,
+ CHECKED_COLUMN,
+ N_COLUMNS
+};
+
+GtkTreeStore *store = gtk_tree_store_new (N_COLUMNS, /* Total number of columns */
+ G_TYPE_STRING, /* Book title */
+ G_TYPE_STRING, /* Author */
+ G_TYPE_BOOLEAN); /* Is checked out? */
+```
+
+Adding data to the model is done using gtk_tree_store_set() or
+gtk_list_store_set(), depending upon which sort of model was
+created. To do this, a #GtkTreeIter must be acquired. The iterator
+points to the location where data will be added.
+
+Once an iterator has been acquired, gtk_tree_store_set() is used to
+apply data to the part of the model that the iterator points to.
+Consider the following example:
+
+``` {.c}
+GtkTreeIter iter;
+
+gtk_tree_store_append (store, &iter, NULL); /* Acquire an iterator */
+
+gtk_tree_store_set (store, &iter,
+ TITLE_COLUMN, "The Principle of Reason",
+ AUTHOR_COLUMN, "Martin Heidegger",
+ CHECKED_COLUMN, FALSE,
+ -1);
+```
+
+Notice that the last argument is -1. This is always done because
+this is a variable-argument function and it needs to know when to stop
+processing arguments. It can be used to set the data in any or all
+columns in a given row.
+
+The third argument to gtk_tree_store_append() is the parent iterator.
+It is used to add a row to a GtkTreeStore as a child of an existing row.
+This means that the new row will only be visible when its parent is visible
+and in its expanded state. Consider the following example:
+
+``` {.c}
+GtkTreeIter iter1; /* Parent iter */
+GtkTreeIter iter2; /* Child iter */
+
+gtk_tree_store_append (store, &iter1, NULL); /* Acquire a top-level iterator */
+gtk_tree_store_set (store, &iter1,
+ TITLE_COLUMN, "The Art of Computer Programming",
+ AUTHOR_COLUMN, "Donald E. Knuth",
+ CHECKED_COLUMN, FALSE,
+ -1);
+
+gtk_tree_store_append (store, &iter2, &iter1); /* Acquire a child iterator */
+gtk_tree_store_set (store, &iter2,
+ TITLE_COLUMN, "Volume 1: Fundamental Algorithms",
+ -1);
+
+gtk_tree_store_append (store, &iter2, &iter1);
+gtk_tree_store_set (store, &iter2,
+ TITLE_COLUMN, "Volume 2: Seminumerical Algorithms",
+ -1);
+
+gtk_tree_store_append (store, &iter2, &iter1);
+gtk_tree_store_set (store, &iter2,
+ TITLE_COLUMN, "Volume 3: Sorting and Searching",
+ -1);
+```
+
+## Creating the view component
+
+While there are several different models to choose from, there is
+only one view widget to deal with. It works with either the list
+or the tree store. Setting up a #GtkTreeView is not a difficult
+matter. It needs a #GtkTreeModel to know where to retrieve its data
+from.
+
+``` {.c}
+GtkWidget *tree;
+
+tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+```
+
+## Colums and cell renderers
+
+Once the #GtkTreeView widget has a model, it will need to know how
+to display the model. It does this with columns and cell renderers.
+
+Cell renderers are used to draw the data in the tree model in a
+way. There are a number of cell renderers that come with GTK,
+including the #GtkCellRendererText, #GtkCellRendererPixbuf and
+the #GtkCellRendererToggle. It is relatively easy to write a
+custom renderer.
+
+A #GtkTreeViewColumn is the object that GtkTreeView uses to organize
+the vertical columns in the tree view. It needs to know the name of
+the column to label for the user, what type of cell renderer to use,
+and which piece of data to retrieve from the model for a given row.
+
+``` {.c}
+GtkCellRenderer *renderer;
+GtkTreeViewColumn *column;
+
+renderer = gtk_cell_renderer_text_new (<!-- -->);
+column = gtk_tree_view_column_new_with_attributes ("Author",
+ renderer,
+ "text", AUTHOR_COLUMN,
+ NULL);
+gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+```
+
+At this point, all the steps in creating a displayable tree have been
+covered. The model is created, data is stored in it, a tree view is
+created and columns are added to it.
+
+## Selection handling
+
+Most applications will need to not only deal with displaying data,
+but also receiving input events from users. To do this, simply get
+a reference to a selection object and connect to the
+#GtkTreeSelection::changed signal.
+
+``` {.c}
+/* Prototype for selection handler callback */
+static void tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data);
+
+/* Setup the selection handler */
+GtkTreeSelection *select;
+
+select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
+gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
+g_signal_connect (G_OBJECT (select), "changed",
+ G_CALLBACK (tree_selection_changed_cb),
+ NULL);
+```
+
+Then to retrieve data for the row selected:
+
+``` {.c}
+static void
+tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ gchar *author;
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter))
+ {
+ gtk_tree_model_get (model, &iter, AUTHOR_COLUMN, &author, -1);
+
+ g_print ("You selected a book by %s\n", author);
+
+ g_free (author);
+ }
+}
+```
+
+## Simple Example
+
+Here is a simple example of using a #GtkTreeView widget in context
+of the other widgets. It simply creates a simple model and view,
+and puts them together. Note that the model is never populated
+with data — that is left as an exercise for the reader.
+More information can be found on this in the #GtkTreeModel section.
+
+``` {.c}
+enum
+{
+ TITLE_COLUMN,
+ AUTHOR_COLUMN,
+ CHECKED_COLUMN,
+ N_COLUMNS
+};
+
+void
+setup_tree (void)
+{
+ GtkTreeStore *store;
+ GtkWidget *tree;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+
+ /* Create a model. We are using the store model for now, though we
+ * could use any other GtkTreeModel */
+ store = gtk_tree_store_new (N_COLUMNS,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN);
+
+ /* custom function to fill the model with data */
+ populate_tree_model (store);
+
+ /* Create a view */
+ tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
+
+ /* The view now holds a reference. We can get rid of our own
+ * reference */
+ g_object_unref (G_OBJECT (store));
+
+ /* Create a cell render and arbitrarily make it red for demonstration
+ * purposes */
+ renderer = gtk_cell_renderer_text_new (<!-- -->);
+ g_object_set (G_OBJECT (renderer),
+ "foreground", "red",
+ NULL);
+
+ /* Create a column, associating the "text" attribute of the
+ * cell_renderer to the first column of the model */
+ column = gtk_tree_view_column_new_with_attributes ("Author", renderer,
+ "text", AUTHOR_COLUMN,
+ NULL);
+
+ /* Add the column to the view. */
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+ /* Second column.. title of the book. */
+ renderer = gtk_cell_renderer_text_new (<!-- -->);
+ column = gtk_tree_view_column_new_with_attributes ("Title",
+ renderer,
+ "text", TITLE_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+ /* Last column.. whether a book is checked out. */
+ renderer = gtk_cell_renderer_toggle_new (<!-- -->);
+ column = gtk_tree_view_column_new_with_attributes ("Checked out",
+ renderer,
+ "active", CHECKED_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
+
+ /* Now we can manipulate the view just like any other GTK widget */
+ ...
+}
+```
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-]>
-<refentry id="TextWidget">
-<refmeta>
-<refentrytitle>Text Widget Overview</refentrytitle>
-<manvolnum>3</manvolnum>
-<refmiscinfo>GTK Library</refmiscinfo>
-</refmeta>
-
-<refnamediv>
-<refname>Text Widget Overview</refname>
-<refpurpose>Overview of GtkTextBuffer, GtkTextView, and friends</refpurpose>
-</refnamediv>
-
-<refsect1>
-<title>Conceptual Overview</title>
-
-<para>
-GTK has an extremely powerful framework for multiline text editing. The
-primary objects involved in the process are #GtkTextBuffer, which represents the
-text being edited, and #GtkTextView, a widget which can display a #GtkTextBuffer.
-Each buffer can be displayed by any number of views.
-</para>
-
-<para>
-One of the important things to remember about text in GTK is that it's in the
-UTF-8 encoding. This means that one character can be encoded as multiple
-bytes. Character counts are usually referred to as
-<firstterm>offsets</firstterm>, while byte counts are called
-<firstterm>indexes</firstterm>. If you confuse these two, things will work fine
-with ASCII, but as soon as your buffer contains multibyte characters, bad
-things will happen.
-</para>
-
-<para>
-Text in a buffer can be marked with <firstterm>tags</firstterm>. A tag is an
-attribute that can be applied to some range of text. For example, a tag might
-be called "bold" and make the text inside the tag bold. However, the tag
-concept is more general than that; tags don't have to affect appearance. They
-can instead affect the behavior of mouse and key presses, "lock" a range of
-text so the user can't edit it, or countless other things. A tag is
-represented by a #GtkTextTag object. One #GtkTextTag can be applied to any
-number of text ranges in any number of buffers.
-</para>
-
-<para>
-Each tag is stored in a #GtkTextTagTable. A tag table defines a set of
-tags that can be used together. Each buffer has one tag table associated with
-it; only tags from that tag table can be used with the buffer. A single tag
-table can be shared between multiple buffers, however.
-</para>
-
-<para>
-Tags can have names, which is convenient sometimes (for example, you can name
-your tag that makes things bold "bold"), but they can also be anonymous (which
-is convenient if you're creating tags on-the-fly).
-</para>
-
-<para>
-Most text manipulation is accomplished with <firstterm>iterators</firstterm>,
-represented by a #GtkTextIter. An iterator represents a position between two
-characters in the text buffer. #GtkTextIter is a struct designed to be
-allocated on the stack; it's guaranteed to be copiable by value and never
-contain any heap-allocated data. Iterators are not valid indefinitely;
-whenever the buffer is modified in a way that affects the number of characters
-in the buffer, all outstanding iterators become invalid. (Note that deleting
-5 characters and then reinserting 5 still invalidates iterators, though you
-end up with the same number of characters you pass through a state with a
-different number).
-</para>
-
-<para>
-Because of this, iterators can't be used to preserve positions across buffer
-modifications. To preserve a position, the #GtkTextMark object is ideal. You
-can think of a mark as an invisible cursor or insertion point; it floats in
-the buffer, saving a position. If the text surrounding the mark is deleted,
-the mark remains in the position the text once occupied; if text is inserted
-at the mark, the mark ends up either to the left or to the right of the new
-text, depending on its <firstterm>gravity</firstterm>. The standard text
-cursor in left-to-right languages is a mark with right gravity, because it
-stays to the right of inserted text.
-</para>
-
-<para>
-Like tags, marks can be either named or anonymous. There are two marks built-in
-to #GtkTextBuffer; these are named <literal>"insert"</literal> and
-<literal>"selection_bound"</literal> and refer to the insertion point and the
-boundary of the selection which is not the insertion point, respectively. If
-no text is selected, these two marks will be in the same position. You can
-manipulate what is selected and where the cursor appears by moving these
-marks around.
-<footnote>
-<para>
-If you want to place the cursor in response to a user action, be sure to use
-gtk_text_buffer_place_cursor(), which moves both at once without causing a
-temporary selection (moving one then the other temporarily selects the range in
-between the old and new positions).
-</para>
-</footnote>
-</para>
-
-<para>
-Text buffers always contain at least one line, but may be empty (that
-is, buffers can contain zero characters). The last line in the text
-buffer never ends in a line separator (such as newline); the other
-lines in the buffer always end in a line separator. Line separators
-count as characters when computing character counts and character
-offsets. Note that some Unicode line separators are represented with
-multiple bytes in UTF-8, and the two-character sequence "\r\n" is also
-considered a line separator.
-</para>
-
-<para>
-Text buffers support undo and redo if gtk_text_buffer_set_enable_undo()
-has been set to %TRUE. Use gtk_text_buffer_undo() or gtk_text_buffer_redo()
-to perform the necessary action. Note that these operations are ignored if
-the buffer is not editable. Developers may want some operations to not be
-undoable. To do this, wrap your changes in
-gtk_text_buffer_begin_irreversible_action() and
-gtk_text_buffer_end_irreversible_action().
-</para>
-
-</refsect1>
-
-
-<refsect1>
-<title>Simple Example</title>
-
-<para>
-The simplest usage of #GtkTextView might look like this:
-<informalexample><programlisting>
- GtkWidget *view;
- GtkTextBuffer *buffer;
-
- view = gtk_text_view_new (<!-- -->);
-
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-
- gtk_text_buffer_set_text (buffer, "Hello, this is some text", -1);
-
- /* Now you might put the view in a container and display it on the
- * screen; when the user edits the text, signals on the buffer
- * will be emitted, such as "changed", "insert_text", and so on.
- */
-</programlisting></informalexample>
-In many cases it's also convenient to first create the buffer with
-gtk_text_buffer_new(), then create a widget for that buffer with
-gtk_text_view_new_with_buffer(). Or you can change the buffer the widget
-displays after the widget is created with gtk_text_view_set_buffer().
-</para>
-
-</refsect1>
-
-<refsect1>
-<title>Example of Changing Text Attributes</title>
-
-<para>
-
-The way to affect text attributes in #GtkTextView is to
-apply tags that change the attributes for a region of text.
-For text features that come from the theme — such as font and
-foreground color — use CSS to override their default values.
-
-<informalexample><programlisting>
- GtkWidget *view;
- GtkTextBuffer *buffer;
- GtkTextIter start, end;
- PangoFontDescription *font_desc;
- GdkRGBA rgba;
- GtkTextTag *tag;
- GtkCssProvider *provider;
- GtkStyleContext *context;
-
- view = gtk_text_view_new (<!-- -->);
-
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-
- gtk_text_buffer_set_text (buffer, "Hello, this is some text", -1);
-
- /* Change default font and color throughout the widget */
- provider = gtk_css_provider_new ();
- gtk_css_provider_load_from_data (provider,
- "textview {"
- " font: 15 serif;"
- " color: green;"
- "}",
- -1);
- context = gtk_widget_get_style_context (view);
- gtk_style_context_add_provider (context,
- GTK_STYLE_PROVIDER (provider),
- GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
-
- /* Change left margin throughout the widget */
- gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 30);
-
- /* Use a tag to change the color for just one part of the widget */
- tag = gtk_text_buffer_create_tag (buffer, "blue_foreground",
- "foreground", "blue", NULL);
- gtk_text_buffer_get_iter_at_offset (buffer, &start, 7);
- gtk_text_buffer_get_iter_at_offset (buffer, &end, 12);
- gtk_text_buffer_apply_tag (buffer, tag, &start, &end);
-</programlisting></informalexample>
-
-</para>
-
-<para>
-The <application>gtk-demo</application> application that comes with
-GTK contains more example code for #GtkTextView.
-</para>
-
-</refsect1>
-
-</refentry>
+++ /dev/null
-<?xml version="1.0"?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
-]>
-<refentry id="TreeWidget">
- <refmeta>
- <refentrytitle>Tree and List Widget Overview</refentrytitle>
- <manvolnum>3</manvolnum>
- <refmiscinfo>GTK Library</refmiscinfo>
- </refmeta>
-
- <refnamediv>
- <refname>Tree and List Widget Overview</refname>
- <refpurpose>Overview of GtkTreeModel, GtkTreeView, and friends</refpurpose>
- </refnamediv>
-
- <refsect1>
- <title>Overview</title>
- <para>
- To create a tree or list in GTK, use the #GtkTreeModel interface in
- conjunction with the #GtkTreeView widget. This widget is
- designed around a <firstterm>Model/View/Controller</firstterm>
- design and consists of four major parts:
- <simplelist>
- <member>The tree view widget (<structname>GtkTreeView</structname>)</member>
- <member>The view column (<structname>GtkTreeViewColumn</structname>)</member>
- <member>The cell renderers (<structname>GtkCellRenderer</structname> etc.)</member>
- <member>The model interface (<structname>GtkTreeModel</structname>)</member>
- </simplelist>
- The <emphasis>View</emphasis> is composed of the first three
- objects, while the last is the <emphasis>Model</emphasis>. One
- of the prime benefits of the MVC design is that multiple views
- can be created of a single model. For example, a model mapping
- the file system could be created for a file manager. Many views
- could be created to display various parts of the file system,
- but only one copy need be kept in memory.
- </para>
- <para>
- The purpose of the cell renderers is to provide extensibility to the
- widget and to allow multiple ways of rendering the same type of data.
- For example, consider how to render a boolean variable. Should it
- render it as a string of "True" or "False", "On" or "Off", or should
- it be rendered as a checkbox?
- </para>
- </refsect1>
- <refsect1>
- <title>Creating a model</title>
- <para>
- GTK provides two simple models that can be used: the #GtkListStore
- and the #GtkTreeStore. GtkListStore is used to model list widgets,
- while the GtkTreeStore models trees. It is possible to develop a new
- type of model, but the existing models should be satisfactory for all
- but the most specialized of situations. Creating the model is quite
- simple:
- </para>
- <informalexample><programlisting><![CDATA[
-GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
-]]></programlisting></informalexample>
- <para>
- This creates a list store with two columns: a string column and a boolean
- column. Typically the 2 is never passed directly like that; usually an
- enum is created wherein the different columns are enumerated, followed by
- a token that represents the total number of columns. The next example will
- illustrate this, only using a tree store instead of a list store. Creating
- a tree store operates almost exactly the same.
- </para>
- <informalexample><programlisting><![CDATA[
-enum
-{
- TITLE_COLUMN,
- AUTHOR_COLUMN,
- CHECKED_COLUMN,
- N_COLUMNS
-};
-
-GtkTreeStore *store = gtk_tree_store_new (N_COLUMNS, /* Total number of columns */
- G_TYPE_STRING, /* Book title */
- G_TYPE_STRING, /* Author */
- G_TYPE_BOOLEAN); /* Is checked out? */
-]]></programlisting></informalexample>
- <para>
- Adding data to the model is done using gtk_tree_store_set() or
- gtk_list_store_set(), depending upon which sort of model was
- created. To do this, a #GtkTreeIter must be acquired. The iterator
- points to the location where data will be added.
- </para>
- <para>
- Once an iterator has been acquired, gtk_tree_store_set() is used to
- apply data to the part of the model that the iterator points to.
- Consider the following example:
- </para>
- <informalexample><programlisting><![CDATA[
-GtkTreeIter iter;
-
-gtk_tree_store_append (store, &iter, NULL); /* Acquire an iterator */
-
-gtk_tree_store_set (store, &iter,
- TITLE_COLUMN, "The Principle of Reason",
- AUTHOR_COLUMN, "Martin Heidegger",
- CHECKED_COLUMN, FALSE,
- -1);
-]]></programlisting></informalexample>
-
- <para>
- Notice that the last argument is -1. This is always done because
- this is a variable-argument function and it needs to know when to stop
- processing arguments. It can be used to set the data in any or all
- columns in a given row.
- </para>
- <para>
- The third argument to gtk_tree_store_append() is the parent iterator. It
- is used to add a row to a GtkTreeStore as a child of an existing row. This
- means that the new row will only be visible when its parent is visible and
- in its expanded state. Consider the following example:
- </para>
- <informalexample><programlisting><![CDATA[
-GtkTreeIter iter1; /* Parent iter */
-GtkTreeIter iter2; /* Child iter */
-
-gtk_tree_store_append (store, &iter1, NULL); /* Acquire a top-level iterator */
-gtk_tree_store_set (store, &iter1,
- TITLE_COLUMN, "The Art of Computer Programming",
- AUTHOR_COLUMN, "Donald E. Knuth",
- CHECKED_COLUMN, FALSE,
- -1);
-
-gtk_tree_store_append (store, &iter2, &iter1); /* Acquire a child iterator */
-gtk_tree_store_set (store, &iter2,
- TITLE_COLUMN, "Volume 1: Fundamental Algorithms",
- -1);
-
-gtk_tree_store_append (store, &iter2, &iter1);
-gtk_tree_store_set (store, &iter2,
- TITLE_COLUMN, "Volume 2: Seminumerical Algorithms",
- -1);
-
-gtk_tree_store_append (store, &iter2, &iter1);
-gtk_tree_store_set (store, &iter2,
- TITLE_COLUMN, "Volume 3: Sorting and Searching",
- -1);
-]]></programlisting></informalexample>
- </refsect1>
-
- <refsect1>
- <title>Creating the view component</title>
- <para>
- While there are several different models to choose from, there is
- only one view widget to deal with. It works with either the list
- or the tree store. Setting up a #GtkTreeView is not a difficult
- matter. It needs a #GtkTreeModel to know where to retrieve its data
- from.
- </para>
- <informalexample><programlisting><![CDATA[
-GtkWidget *tree;
-
-tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
-]]></programlisting></informalexample>
-
- <refsect2>
- <title>Columns and cell renderers</title>
- <para>
- Once the #GtkTreeView widget has a model, it will need to know how
- to display the model. It does this with columns and cell renderers.
- </para>
- <para>
- Cell renderers are used to draw the data in the tree model in a
- way. There are a number of cell renderers that come with GTK,
- including the #GtkCellRendererText, #GtkCellRendererPixbuf and
- the #GtkCellRendererToggle.
- It is relatively easy to write a custom renderer.
- </para>
- <para>
- A #GtkTreeViewColumn is the object that GtkTreeView uses to organize
- the vertical columns in the tree view. It needs to know the name of
- the column to label for the user, what type of cell renderer to use,
- and which piece of data to retrieve from the model for a given row.
- </para>
- <informalexample><programlisting>
-GtkCellRenderer *renderer;
-GtkTreeViewColumn *column;
-
-renderer = gtk_cell_renderer_text_new (<!-- -->);
-column = gtk_tree_view_column_new_with_attributes ("Author",
- renderer,
- "text", AUTHOR_COLUMN,
- NULL);
-gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
-</programlisting></informalexample>
- <para>
- At this point, all the steps in creating a displayable tree have been
- covered. The model is created, data is stored in it, a tree view is
- created and columns are added to it.
- </para>
- </refsect2>
-
- <refsect2>
- <title>Selection handling</title>
- <para>
- Most applications will need to not only deal with displaying data, but
- also receiving input events from users. To do this, simply get a
- reference to a selection object and connect to the
- #GtkTreeSelection::changed signal.
- </para>
- <informalexample><programlisting><![CDATA[
-/* Prototype for selection handler callback */
-static void tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data);
-
-/* Setup the selection handler */
-GtkTreeSelection *select;
-
-select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
-gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
-g_signal_connect (G_OBJECT (select), "changed",
- G_CALLBACK (tree_selection_changed_cb),
- NULL);
-]]></programlisting></informalexample>
- <para>
- Then to retrieve data for the row selected:
- </para>
- <informalexample><programlisting><![CDATA[
-static void
-tree_selection_changed_cb (GtkTreeSelection *selection, gpointer data)
-{
- GtkTreeIter iter;
- GtkTreeModel *model;
- gchar *author;
-
- if (gtk_tree_selection_get_selected (selection, &model, &iter))
- {
- gtk_tree_model_get (model, &iter, AUTHOR_COLUMN, &author, -1);
-
- g_print ("You selected a book by %s\n", author);
-
- g_free (author);
- }
-}
-]]></programlisting></informalexample>
- </refsect2>
- </refsect1>
-
- <refsect1>
- <title>Simple Example</title>
- <para>
- Here is a simple example of using a #GtkTreeView widget in context
- of the other widgets. It simply creates a simple model and view,
- and puts them together. Note that the model is never populated
- with data — that is left as an exercise for the reader.
- More information can be found on this in the #GtkTreeModel section.
- <informalexample><programlisting>
-enum
-{
- TITLE_COLUMN,
- AUTHOR_COLUMN,
- CHECKED_COLUMN,
- N_COLUMNS
-};
-
-void
-setup_tree (void)
-{
- GtkTreeStore *store;
- GtkWidget *tree;
- GtkTreeViewColumn *column;
- GtkCellRenderer *renderer;
-
- /* Create a model. We are using the store model for now, though we
- * could use any other GtkTreeModel */
- store = gtk_tree_store_new (N_COLUMNS,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_BOOLEAN);
-
- /* custom function to fill the model with data */
- populate_tree_model (store);
-
- /* Create a view */
- tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
-
- /* The view now holds a reference. We can get rid of our own
- * reference */
- g_object_unref (G_OBJECT (store));
-
- /* Create a cell render and arbitrarily make it red for demonstration
- * purposes */
- renderer = gtk_cell_renderer_text_new (<!-- -->);
- g_object_set (G_OBJECT (renderer),
- "foreground", "red",
- NULL);
-
- /* Create a column, associating the "text" attribute of the
- * cell_renderer to the first column of the model */
- column = gtk_tree_view_column_new_with_attributes ("Author", renderer,
- "text", AUTHOR_COLUMN,
- NULL);
-
- /* Add the column to the view. */
- gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
-
- /* Second column.. title of the book. */
- renderer = gtk_cell_renderer_text_new (<!-- -->);
- column = gtk_tree_view_column_new_with_attributes ("Title",
- renderer,
- "text", TITLE_COLUMN,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
-
- /* Last column.. whether a book is checked out. */
- renderer = gtk_cell_renderer_toggle_new (<!-- -->);
- column = gtk_tree_view_column_new_with_attributes ("Checked out",
- renderer,
- "active", CHECKED_COLUMN,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
-
- /* Now we can manipulate the view just like any other GTK widget */
- ...
-}
- </programlisting></informalexample>
- </para>
- </refsect1>
-</refentry>